# 一、基础条件查询
# 1 基本查询
# get 查询单一结果，如果不存在会抛出模型类.DoesNotExist 异常。
from book.models import BookInfo, PeopleInfo
# 查询 id=1 的 图书
BookInfo.objects.get(id=1)
# 如果 id=5 不存在，抛异常 DoesNotExist
BookInfo.objects.get(id=5)

# all 查询多个结果。
BookInfo.objects.all()

# count 查询结果数量。
# 查询 图书 总的数量
BookInfo.objects.count()
# 查询 人物总的数量
PeopleInfo.objects.count()


# 2. 过滤查询
"""
实现SQL中的where功能，包括：
     - filter过滤出多个结果
     - exclude排除符合条件的所有结果
     - get提取出单个结果
     对于过滤条件的使用，上述三个方法相同，建议以filter进行讲解。
     
过滤条件的实现语法如下：
    属性名称__比较运算符=值
    属性名称和比较运算符间使用两个下划线，所以属性名不能包括多个下划线
"""

# 1） 相等 -- exact：表示判等。
# 例：查询编号为1的图书
BookInfo.objects.get(id__exact=1)
# 简写
BookInfo.objects.get(id=1)
# pk：primary(主要的)key（键）
BookInfo.objects.get(pk=1)

# 2）模糊查询 --contains:是否包含.
# 例：查询 书名 包含‘传’的图书
BookInfo.objects.filter(name__contains='传')

# startswith, endswith, 以指定值开头或结尾。
# 例：查询 书名 以'部'结尾的图书
BookInfo.objects.filter(name__endswith='部')
# 例：查询 书名 以'射'结尾的图书
BookInfo.objects.filter(name__startswith='射')
# 以上运算符都区分大小。在这些运算符前加上i表示不区分大小写：如iexact, icontains, istartswith, iendswith。

# 3) 空查询 -- isnull：是否为null
# 例：查询 书名 为空的图书。
BookInfo.objects.filter(name__isnull=True)
# 例：查询 书名 不为空的图书。
BookInfo.objects.filter(name__isnull=False)

# 4) 范围 --in：是否在范围内。
# 例：查询 编号id 为1或3或5的图书
BookInfo.objects.filter(id__in=[1, 3, 5])

# 5）比较查询
"""
 gt大于 (greater than)
 gte大于等于 (greater than equal)
 lt小于 (less than)
 lte小于等于 (less than equal)
 """
# 例：查询 编号id 大于3的图书
BookInfo.objects.filter(id__gt=3)
BookInfo.objects.filter(id__lte=2)

# 不等于的运算符，使用exclude()过滤器。
# 例：查询id不等于3的图书
BookInfo.objects.exclude(id=3)

# 6）日期查询
# 以year, month, day, week_day, hour, minute, second, 对日期时间类型的值进行过滤。
# 例： 查询pub_date 是1980年 发表的图书。
BookInfo.objects.filter(pub_date__year=1980)
# 例：查询pub_date在1990-1-1后 发表的图书
BookInfo.objects.filter(pub_date__gt='1990-1-1')


# 二、F 和 Q 对象
"""
1. F 对象
      之前的查询都是对象的属性与常量值比较，两个属性怎么比较呢？答：使用 F 对象，被定义在django.db.models中。

语法如下：
     F（属性名）
例：查询阅读量大量等于评论量的图书。
"""
# 导包
from django.db.models import F, Q
# 查询 阅读量readcount 大于等于 评论量commentcount 的图书
BookInfo.objects.filter(readcount__gte=F('commentcount'))

# 可以在 F 对象上使用算数运算。
# 查询 阅读量 readcount 大于等于 2 倍评论量 commentcount 的图书。
BookInfo.objects.filter(readcount__gte=F('commentcount')*2)

'''
2. Q对象
    多个过滤器逐个调用表示逻辑与关系，同 sql 语句中 where 部分的 and 关键字。
'''
# 例：查询 阅读量 readcount 大于 20，并且 编号 id 小于 3 的图书。
BookInfo.objects.filter(readcount__gt=20, id__lt=3)

# 查询阅读量 readcount 大于 20，或 编号 id 小于 3 的图书，只能使用 Q 对象实现
BookInfo.objects.filter(Q(readcount__gt=20) | Q(id__lt=3))

# 查询编号 id 不等于 3 的图书。
# Q 对象还可以使用～操作符，表示非not。
BookInfo.objects.filter(~Q(id=3))
# 查询编号 id 不等于 1 和 3 的图书。
BookInfo.objects.filter(~Q(id__in=[1, 3]))


# 三、聚合函数和排序函数
# 1. 使用 aggregate () 过滤器调用聚合函数，聚合函数：Avg 平均，Count 数量，Max 最大，Min 最小，Sum 求和，被定义在 django.db.models 中。
from django.db.models import Sum, Max, Avg, Count, Min
# 例：查询 图书的 总阅读量 readcount。
BookInfo.objects.aggregate(Sum('readcount'))
# 查询 图书的 最大评论量 commentcount。
BookInfo.objects.aggregate(Max('commentcount'))
# 查询图书 平均 阅读量 readcount
BookInfo.objects.aggregate(Avg('readcount'))

# 2. 排序
# 使用 order_by 对结果进行排序
# 默认 按照主键 升序排列
BookInfo.objects.all()
# 按照给定的 字段名 阅读量 readcount（列名）进行 升序排序
BookInfo.objects.all().order_by('readcount')

# 按照给定的 字段名 评论量 commentcount（列名）进行 降序排序
BookInfo.objects.all().order_by('-commentcount')
# 按照给定的 字段名 出版日期 pub_date（列名）进行 升序 / 降序排序
BookInfo.objects.all().order_by('pub_date')
BookInfo.objects.all().order_by('-pub_date')

# 四、关联查询
# 1、关联查询
# 1.1 由一到多的访问语法：一对应的模型类对象。多对应的模型类小写_set
# 例：查询 书籍 id 为 1 的 所有人物信息
# 一对应的模型类对象
book = BookInfo.objects.get(id=1)
# 对象.多对应的模型类小写_set，通过 all () 返回所有人物
book.peopleinfo_set.all()

# 例：查询 书籍名称 name 为 '雪山飞狐'的 所有人物信息
book = BookInfo.objects.get(name='雪山飞狐')
book.peopleinfo_set.all()

# 1.2 由多到一的访问语法：多对应的模型类对象。多对应的模型类中的关系类属性名
# 例：查询 人物 id 为 1 的 书籍信息
# 多对应的模型类对象
people = PeopleInfo.objects.get(id=1)
#对象.多对应的模型类中的关系类属性名
people.book

# 1.3 访问一对应的模型类关联对象的 id 语法： 多对应的模型类对象。关联类属性_id
# 例：查询 id=1 的人物 所属 图书的 id
people.book_id

# 例：查询 人物名字 name 为 ' 虚竹 ' 的 书籍信息
people = PeopleInfo.objects.get(name='虚竹')
people.book

# 2. 关联过滤查询
# 2.1 由多模型类条件查询一模型类数据:
"""语法如下：
       关联模型类名小写__属性名__条件运算符 = 值
注意：如果没有 "__运算符" 部分，表示等于。
"""
# 查询图书，要求图书 人物 name 为 "郭靖"
book = BookInfo.objects.get(peopleinfo__name='郭靖')
# 查询图书，要求图书中 人物的 描述 description 包含 "八"
books = BookInfo.objects.filter(peopleinfo__description__contains='八')

# 2.2 由一模型类条件查询多模型类数据:
"""语法如下：
       一模型类关联属性名__一模型类属性名__条件运算符 = 值
注意：如果没有 "__运算符" 部分，表示等于。
"""
# 查询 书名 name 为 "天龙八部" 的 所有人物
peoples = PeopleInfo.objects.filter(book__name='天龙八部')

# 查询 图书阅读量 readcount 大于 30 的 所有人物
peoples = PeopleInfo.objects.filter(book__readcount__gt=30)
